
package com.ttomato.game.framework;

import java.util.ArrayList;
import java.util.List;

import android.R.integer;
import android.util.FloatMath;

public class SpatialHashGrid {

    private static final int GAMEOBJECT_NUMBERS_PER_CELL = 10;

    List<GameObject>[] mDynamicCells;
    List<GameObject>[] mStaticCells;
    int mCellsPerRow;
    int mCellsPerCol;

    float mCellSize;
    int[] mCellIds = new int[4];
    List<GameObject> mFoundObjects;

    public SpatialHashGrid(float worldWidth, float worldHeight, float cellSize) {
        mCellSize = cellSize;
        mCellsPerRow = (int) FloatMath.ceil(worldHeight / cellSize);
        mCellsPerCol = (int) FloatMath.ceil(worldHeight / cellSize);
        int cellNumbers = mCellsPerCol * mCellsPerRow;
        mDynamicCells = new List[cellNumbers];
        mStaticCells = new List[cellNumbers];

        for (int i = 0; i < cellNumbers; i++) {
            mDynamicCells[i] = new ArrayList<GameObject>(GAMEOBJECT_NUMBERS_PER_CELL);
            mStaticCells[i] = new ArrayList<GameObject>(GAMEOBJECT_NUMBERS_PER_CELL);
        }
        mFoundObjects = new ArrayList<GameObject>(GAMEOBJECT_NUMBERS_PER_CELL);

    }

    public void insertStaticObejct(GameObject object) {
        int[] cellIds = getCellIds(object);

        int i = 0;
        int cellId = -1;
        while (i <= 3 && (cellId = cellIds[i++]) != -1) {
            mStaticCells[cellId].add(object);
        }
    }

    public void insertDynamicObject(GameObject obj) {
        int[] cellIds = getCellIds(obj);
        int i = 0;
        int cellId = -1;
        while (i <= 3 && (cellId = cellIds[i++]) != -1) {
            mDynamicCells[cellId].add(obj);
        }
    }

    public void removeObject(GameObject object) {
        int[] cellIds = getCellIds(object);
        int i = 0;
        int cellId = -1;
        while (i <= 3 && (cellId = cellIds[i++]) != -1) {
            mDynamicCells[cellId].remove(object);
            mStaticCells[cellId].remove(object);
        }
    }

    public void clearDynamicCells(GameObject obj) {
        int len = mDynamicCells.length;
        for (int i = 0; i < len; i++) {
            mDynamicCells[i].clear();
        }
    }

    public List<GameObject> getPotentialColliders(GameObject gameObject) {
        int[] cellIds = getCellIds(gameObject);
        int i = 0;
        int cellId = -1;
        while (i <= 3 && (cellId = cellIds[i]) != -1) {
            int len = mDynamicCells[cellId].size();
            for (int j = 0; j < len; j++) {
                GameObject object = mDynamicCells[cellId].get(j);
                if (!mFoundObjects.contains(object)) {
                    mFoundObjects.add(object);
                }
            }

            len = mStaticCells[cellId].size();
            for (int j = 0; j < len; j++) {
                GameObject object = mStaticCells[cellId].get(j);
                if (!mFoundObjects.contains(object)) {
                    mFoundObjects.add(object);
                }
            }
        }

        return mFoundObjects;
    }

    public int[] getCellIds(GameObject object) {
        int x1 = (int) FloatMath.floor(object.mBounds.mLowerLeft.mX / mCellSize);
        int y1 = (int) FloatMath.floor(object.mBounds.mLowerLeft.mY / mCellSize);
        int x2 = (int) FloatMath.floor((object.mBounds.mLowerLeft.mX + object.mBounds.mWidth)
                / mCellSize);
        int y2 = (int) FloatMath.floor((object.mBounds.mLowerLeft.mY + object.mBounds.mHeight)
                / mCellSize);

        if (x1 == x2 && y1 == y2) {
            if (x1 > 0 && x1 < mCellsPerRow && y1 > 0 && y1 < mCellsPerCol) {
                mCellIds[0] = x1 + mCellsPerCol * y1;
            } else {
                mCellIds[0] = -1;
            }
            mCellIds[1] = -1;
            mCellIds[2] = -1;
            mCellIds[3] = -1;
        } else if (x1 == x2) {
            int i = 0;
            if (x1 > 0 && x1 < mCellsPerRow) {
                if (y1 > 0 && y1 < mCellsPerCol) {
                    mCellIds[i++] = x1 + y1 * mCellsPerRow;
                }
                if (y2 > 0 && y2 < mCellsPerCol) {
                    mCellIds[i++] = x1 + y2 * mCellsPerRow;
                }
            }
            while (i <= 3) {
                mCellIds[i++] = -1;
            }
        } else if (y1 == y2) {
            int i = 0;
            if (y1 > 0 && y1 < mCellsPerCol) {
                if (x1 > 0 && x1 < mCellsPerRow) {
                    mCellIds[i++] = x1 + y1 * mCellsPerRow;
                }
                if (x2 > 0 && x2 < mCellsPerRow) {
                    mCellIds[i++] = x2 + y1 * mCellsPerRow;
                }
            }
            while (i <= 3) {
                mCellIds[i++] = -1;
            }
        } else {
            int i = 0;
            int y1CellsPerRow = y1 * mCellsPerRow;
            int y2CellsPerRow = y2 * mCellsPerRow;
            if (x1 > 0 && x1 < mCellsPerRow && y1 > 0 && y1 < mCellsPerCol) {
                mCellIds[i++] = x1 + y1CellsPerRow;
            }

            if (x2 > 0 && x2 < mCellsPerRow && y1 > 0 && y1 < mCellsPerCol) {
                mCellIds[i++] = x2 + y1CellsPerRow;
            }

            if (x1 > 0 && x1 < mCellsPerRow && y2 > 0 && y2 < mCellsPerCol) {
                mCellIds[i++] = x1 + y2CellsPerRow;
            }

            if (x2 > 0 && x2 < mCellsPerRow && y2 > 0 && y2 < mCellsPerCol) {
                mCellIds[i++] = x2 + y2CellsPerRow;
            }
            while (i <= 3) {
                mCellIds[i++] = -1;
            }
        }

        return mCellIds;
    }
}
